#include "outline/outline.h"
#include <algorithm>
#include <functional>

namespace outline {

template <typename T>
double length(std::vector< point<T> > const & polyline)
{
	if (polyline.size() <= 1)
		return 0;
	double l = 0;
	typename std::vector< point<T> >::const_iterator i = polyline.begin(), p = i;
	for (++i; i != polyline.end(); ++i) {
		l += abs(*i - *p);
		p = i;
	}
	return l;
}

template double length(outline_us const & polyline);
template double length(outline_s const & polyline);
template double length(outline_i const & polyline);
template double length(outline_f const & polyline);
template double length(outline_d const & polyline);

template <typename T, typename R>
R length(std::vector< point<T> > const & polyline, std::vector<R> & partial_lengths, bool normalize)
{
	partial_lengths.resize(polyline.size());
	if (polyline.empty())
		return 0;
	if (polyline.size() == 1) {
		partial_lengths[0] = 0;
		return 0;
	}

	R l = 0;
	typename std::vector<R>::iterator o = partial_lengths.begin();
	*o = 0;
	typename std::vector< point<T> >::const_iterator i = polyline.begin(), p = i;
	for (++i, ++o; i != polyline.end(); ++i, ++o) {
		l += abs(point<R>(*i) - point<R>(*p)); ///< remember about unsigned types
		*o = l;
		p = i;
	}

	if (normalize) {
		assert(partial_lengths.front() == 0);
		std::transform(
			partial_lengths.begin() + 1, partial_lengths.end() - 1,
			partial_lengths.begin() + 1,
			std::bind2nd(std::divides<R>(), l));
		partial_lengths.back() = 1;
	}

	return l;
}

template float  length(outline_us const & polyline, std::vector<float>  & partial_lengths, bool normalize);
template float  length(outline_s const & polyline,  std::vector<float>  & partial_lengths, bool normalize);
template float  length(outline_i const & polyline,  std::vector<float>  & partial_lengths, bool normalize);
template float  length(outline_f const & polyline,  std::vector<float>  & partial_lengths, bool normalize);
template double length(outline_d const & polyline,  std::vector<double> & partial_lengths, bool normalize);

} //namespace outline
